home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / YICN23.ZIP / SOURCE / PLAY_CMF.CPP < prev    next >
C/C++ Source or Header  |  1993-02-14  |  8KB  |  365 lines

  1. /*
  2.  * Copyrighted as an unpublished work.
  3.  * (c) Copyright 1991 Brian Smith
  4.  * All rights reserved.
  5.  *
  6.  * Read the LICENSE file for details on distribution and use.
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <fcntl.h>
  12. #include <dos.h>
  13. #include <alloc.h>
  14. #include <io.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17.  
  18. #include "sb.h"
  19.  
  20. #define TRUE  1
  21. #define FALSE 0
  22.  
  23. #define lobyte(X)   (((unsigned char *)&X)[0])
  24. #define hibyte(X)   (((unsigned char *)&X)[1])
  25.  
  26. /* Globals */
  27. int fm_herz;        /* clock ticks per second */
  28. int tempo;          /* clock ticks per quarter note */
  29. int fm_fd;
  30. int note_on[22];
  31. char **instrument_table;
  32. int note_table[12] = {
  33.     343,
  34.     363,
  35.     385,
  36.     408,
  37.     432,
  38.     458,
  39.     485,
  40.     514,
  41.     544,
  42.     577,
  43.     611,
  44.     647
  45.     };
  46.  
  47.  
  48.  
  49.  
  50. /* check for "CTMF" in first four bytes of file */
  51. int verify_cmf(int fd)
  52. {
  53.     char idbuf[5];
  54.  
  55.     /* get id */
  56.     lseek(fd, 0, SEEK_SET);
  57.     if (read(fd, idbuf, 4) != 4)
  58.         return(FALSE);
  59.     
  60.     /* compare to standard id */
  61.     idbuf[4] = (char)0;
  62.     if (strcmp(idbuf, "CTMF") != 0)
  63.         return(FALSE);
  64.     
  65.     return(TRUE);
  66. }
  67.  
  68. int get_instruments(int fd)
  69. {
  70.     int offset;
  71.     int num_instruments;
  72.     int i;
  73.     int rc;
  74.     int fnum, block, note;
  75.     unsigned char tmp_byte;
  76.  
  77.     /* get offset of instrument block */
  78.     offset = 0;
  79.     lseek(fd, 0x06, SEEK_SET);
  80.     read(fd, &tmp_byte, 1);
  81.     lobyte(offset) = tmp_byte;
  82.     read(fd, &tmp_byte, 1);
  83.     hibyte(offset) = tmp_byte;
  84.  
  85.     /* get number of instruments */
  86.     num_instruments = 0;
  87.     lseek(fd, 0x24, SEEK_SET);
  88.     read(fd, &tmp_byte, 1);
  89.     lobyte(num_instruments) = tmp_byte;
  90.     read(fd, &tmp_byte, 1);
  91.     hibyte(num_instruments) = tmp_byte;
  92.  
  93.     /* allocate space */
  94.     instrument_table = (char **)malloc(sizeof(int *) * num_instruments);
  95.  
  96.     /* read each instrument */
  97.     lseek(fd, (long)offset, SEEK_SET);
  98.     for (i=0; i< num_instruments; i++)
  99.     {
  100.         /* allocate space */
  101.         instrument_table[i] = (char *)malloc(16);
  102.  
  103.         /* set instrument characteristics */
  104.         read(fd, instrument_table[i], 16);
  105.     }
  106.  
  107.     return(0);
  108. }
  109.  
  110.  
  111. /*
  112.  * get and set timing parameters
  113.  */
  114. int set_timing(int fd)
  115. {
  116.     unsigned char tmp_byte;
  117.  
  118.     /* get tempo */
  119.     tempo = 0;
  120.     lseek(fd, 0x0C, SEEK_SET);
  121.     read(fd, &tmp_byte, 1);
  122.     tempo = (unsigned int)tmp_byte;
  123.     read(fd, &tmp_byte, 1);
  124.     tempo += (unsigned int)tmp_byte << 8;
  125.  
  126.     /* get herz of timing clock */
  127.     fm_herz = 0;
  128.     lseek(fd, 0x0C, SEEK_SET);
  129.     read(fd, &tmp_byte, 1);
  130.     fm_herz = (unsigned int)tmp_byte;
  131.     read(fd, &tmp_byte, 1);
  132.     fm_herz += (unsigned int)tmp_byte << 8;
  133.     
  134.     return(0);
  135. }
  136.  
  137.  
  138. /*
  139.  * read a variable length scalar in MIDI format
  140.  */
  141. int ReadVarLen(int fd)
  142. {
  143.     int value;
  144.     unsigned char tmp_byte;
  145.  
  146.     if (read(fd, &tmp_byte, 1) == 0)
  147.         return(-1);
  148.     value = (int)tmp_byte;
  149.     if (tmp_byte & 0x80)
  150.     {
  151.         value &= 0x7F;
  152.         do
  153.         {
  154.             if (read(fd, &tmp_byte, 1) == 0)
  155.                 return(-1);
  156.             value = (value << 7) + (tmp_byte & 0x7F);
  157.         } while (tmp_byte & 0x80);
  158.     }
  159.  
  160.     return(value);
  161. }
  162.  
  163.  
  164. /*
  165.  * load an instrument from the instrument table into the SoundBlaster
  166.  */
  167. int load_instrument(int channel, int instrument)
  168. {
  169.     int rc;
  170.  
  171.     /* error check! */
  172.     if ((channel <0) || (channel >= 9))
  173.         return 0;
  174.  
  175.     /* abort instrument if being loaded */
  176.     if (note_on[channel])
  177.     Sb_FM_Key_Off(channel);
  178.  
  179.     /* set instrument characteristics */
  180.     Sb_FM_Set_Voice(channel,instrument_table[instrument]);
  181.     return(0);
  182. }
  183.  
  184.  
  185. /*
  186.  * process a midi event
  187.  */
  188. int process_event(int fd)
  189. {
  190.     int rc, channel;
  191.     unsigned char tmp_byte;
  192.     static int status = -1;
  193.  
  194.     /* get status byte */
  195.     read(fd, &tmp_byte, 1);
  196.     if (tmp_byte & 0x80)
  197.     {
  198.         status = (unsigned int)tmp_byte;
  199.     }
  200.     else
  201.     {
  202.         /* running status, so back up one */
  203.         if (status == -1)
  204.         {
  205.             printf("ERROR in cmf file. Running status at beginning of file\n");
  206.             exit(-1);
  207.         }
  208.         lseek(fd, -1, SEEK_CUR);
  209.     }
  210.     
  211.     /* switch different events */
  212.     switch (status & 0xF0)
  213.     {
  214.         case 0x80:
  215.             /* turn note off */
  216.         channel = status & 0x0f;
  217.         Sb_FM_Key_Off(channel);
  218.         note_on[channel] = 0;
  219.  
  220.             /* waste two bytes */
  221.             read(fd, &tmp_byte, 1);
  222.             read(fd, &tmp_byte, 1);
  223.             break;
  224.         case 0x90:
  225.             /* get note */
  226.             read(fd, &tmp_byte, 1);
  227.             /* determine note */
  228.  
  229.             /* turn note on */
  230.         channel = status & 0x0f;
  231.         if (note_on[channel])
  232.         Sb_FM_Key_Off(channel);
  233.         note_on[channel] = 1;
  234.         Sb_FM_Key_On(channel,note_table[tmp_byte % 12],(tmp_byte/12) & 7);
  235.  
  236.             /* waste a bytes */
  237.             read(fd, &tmp_byte, 1);
  238.             break;
  239.         case 0xA0:
  240.             printf("polyphonic key pressure: not handled\n");
  241.             /* waste two bytes */
  242.             read(fd, &tmp_byte, 1);
  243.             read(fd, &tmp_byte, 1);
  244.             break;
  245.         case 0xB0:
  246.             printf("control change: not handled\n");
  247.             /* waste two bytes */
  248.             read(fd, &tmp_byte, 1);
  249.             read(fd, &tmp_byte, 1);
  250.             break;
  251.         case 0xC0:
  252.             /* change the instrument on a channel */
  253.             read(fd, &tmp_byte, 1);
  254.             load_instrument(status&0x0F, tmp_byte & 0x0F);
  255.             break;
  256.         case 0xD0:
  257.             printf("Channel Pressure: not handled\n");
  258.             /* waste a byte */
  259.             read(fd, &tmp_byte, 1);
  260.             break;
  261.         case 0xE0:
  262.             printf("Pitch Wheel Change: not handled\n");
  263.             /* waste two bytes */
  264.             read(fd, &tmp_byte, 1);
  265.             read(fd, &tmp_byte, 1);
  266.             break;
  267.         case 0xF0:
  268.             printf("System Exclusive: not handled\n");
  269.             /* waste two bytes */
  270.             read(fd, &tmp_byte, 1);
  271.             read(fd, &tmp_byte, 1);
  272.             break;
  273.         default:
  274.             printf("internal program error\n");
  275.             /* waste two bytes */
  276.             read(fd, &tmp_byte, 1);
  277.             read(fd, &tmp_byte, 1);
  278.             break;
  279.     }
  280.  
  281.  
  282.     return(0);
  283. }
  284. /*
  285.  * seek to the midi stream and handle midi events for the song
  286.  */
  287. int play_song(int fd)
  288. {
  289.     int offset;
  290.     unsigned char tmp_byte;
  291.     int delta;
  292.  
  293.     /* get offset of music stream */
  294.     lseek(fd, 8, SEEK_SET);
  295.     read(fd, &tmp_byte, 1);
  296.     offset = (unsigned int)tmp_byte;
  297.     read(fd, &tmp_byte, 1);
  298.     offset += (unsigned int)tmp_byte << 8;
  299.     lseek(fd, offset, SEEK_SET);
  300.  
  301.     /* process till EOF */
  302.     while(1)
  303.     {
  304.         /* get delta time */
  305.         delta = ReadVarLen(fd);
  306.         if (delta == -1)
  307.             break;
  308.  
  309.         /* wait delta */
  310.         if (delta > 0)
  311.         delay((double)delta/(double)fm_herz * 1000);
  312.  
  313.         /* process midi event */
  314.         process_event(fd);
  315.     }
  316.  
  317.  
  318.     return(0);
  319. }
  320.  
  321.  
  322.  
  323.  
  324.  
  325. int main(int argc, char **argv)
  326. {
  327.     int cmf_fd;
  328.  
  329.     if (argc != 2)
  330.     {
  331.         printf("usage: %s <cmf file>\n", argv[0]);
  332.         exit(-1);
  333.     }
  334.  
  335.     /* open cmf file */
  336.     cmf_fd = open(argv[1], O_RDONLY);
  337.     if (cmf_fd == -1)
  338.     {
  339.         printf("usage: %s <cmf file>\n", argv[0]);
  340.         exit(-1);
  341.     }
  342.  
  343.     /* verify that file is a cmf file */
  344.     if (!verify_cmf(cmf_fd))
  345.     {
  346.         printf("file was not a cmf file\n");
  347.         printf("usage: %s <cmf file>\n", argv[0]);
  348.         exit(-1);
  349.     }
  350.  
  351.     /* read and set instruments from cmf file */
  352.     get_instruments(cmf_fd);
  353.  
  354.     /* get timing */
  355.     set_timing(cmf_fd);
  356.  
  357.     /* open soundblaster fm chips */
  358.     Sb_FM_Reset();
  359.  
  360.     /* play song */
  361.     play_song(cmf_fd);
  362.  
  363.     return(0);
  364. }
  365.